package service

import (
	"context"
	"fmt"
	"time"

	"bmember/pkg/util"

	"bmember/internal/object"

	"bmember/internal/dao"
	"bmember/internal/model"

	pb "bmember/api/pb/server"
	"bmember/pkg/lueerror"
)

// 将查询相关置于该文件下

// GetMemberOpenIdByMemberId 检索用户openid, appid
func (srv *memberSrv) GetMemberOpenIdByMemberId(ctx context.Context, memberId int64, bilinApp string) (*pb.MemberOpenIdGetReply, lueerror.LueError) {
	app := model.GetInnerChannel(bilinApp)
	channels, err := dao.GetLoginChannelDao().GetOpenIdByMemberApp(ctx, memberId, app)
	if err != nil {
		return nil, lueerror.DbErr(err)
	}
	if len(channels) == 0 {
		return nil, lueerror.LoginChannelNotExist(fmt.Errorf("用户 %d,渠道 %s 不存在", memberId, bilinApp))
	}
	// 如果存在，取第一条
	return &pb.MemberOpenIdGetReply{
		MemberId: channels[0].MemberId,
		OpenId:   channels[0].OpenId,
		AppId:    channels[0].AppId,
	}, nil
}

// SearchMembersMobileNickname 检索用户名，手机号
func (srv *memberSrv) SearchMembersMobileNickname(ctx context.Context, brandId int64, mobile, nickname string) (*pb.MemberMobileNicknameListReply, lueerror.LueError) {
	mbs, err := dao.GetMemberDao().SearchMemberByMobileNickname(ctx, brandId, mobile, nickname)
	if err != nil {
		return nil, lueerror.DbErr(err)
	}
	rMems := make([]*pb.MemberMobileNickname, len(mbs))
	for idx, mem := range mbs {
		rMems[idx] = &pb.MemberMobileNickname{
			MemberId: mem.Id,
			Nickname: mem.Nickname,
			Mobile:   mem.Mobile,
		}
	}
	return &pb.MemberMobileNicknameListReply{Members: rMems}, nil
}

// GetMembersMobileNickname 根据ids 获取用户名，手机号
func (srv *memberSrv) GetMembersMobileNickname(ctx context.Context, memberIds []int64) (*pb.MemberMobileNicknameListReply, lueerror.LueError) {
	mbs, err := dao.GetMemberDao().GetMobileNicknameByIds(ctx, memberIds)
	if err != nil {
		return nil, lueerror.DbErr(err)
	}
	rMems := make([]*pb.MemberMobileNickname, len(mbs))
	for idx, mem := range mbs {
		rMems[idx] = &pb.MemberMobileNickname{
			MemberId: mem.Id,
			Nickname: mem.Nickname,
			Mobile:   mem.Mobile,
		}
	}
	return &pb.MemberMobileNicknameListReply{Members: rMems}, nil
}

func (srv *memberSrv) loadCardNameMap(ctx context.Context, brandId int64) (map[int64]string, lueerror.LueError) {
	cards, err := dao.GetCardDao().GetAccountCardsNameByBrand(ctx, brandId)
	if err != nil {
		return nil, lueerror.DbErr(err)
	}
	ret := make(map[int64]string, len(cards))
	for _, c := range cards {
		ret[c.Id] = c.Name
	}
	return ret, nil
}

// AdminSearchMembers 管理后台会员搜索
func (srv *memberSrv) AdminSearchMembers(ctx context.Context, brandId, cardId, memberId int64, nickname, mobile string, pg object.Pagination) (*pb.AdminSearchMembersReply, lueerror.LueError) {
	mems, total, err := dao.GetMemberDao().SearchMembersForAdmin(ctx, brandId, cardId, memberId, nickname, mobile, pg)
	if err != nil {
		return nil, lueerror.DbErr(err)
	}
	cardMap, errL := srv.loadCardNameMap(ctx, brandId)
	if errL != nil {
		return nil, errL
	}
	rMems := make([]*pb.AdminMemberListItem, len(mems))
	for idx, m := range mems {
		cardName, ok := cardMap[m.CardId]
		if !ok {
			cardName = "--"
		}
		rMems[idx] = &pb.AdminMemberListItem{
			MemberId:  m.MemberId,
			BrandId:   m.BrandId,
			Nickname:  m.Nickname,
			Mobile:    m.Mobile,
			CardId:    m.CardId,
			CardName:  cardName,
			Balance:   m.Balance,
			Integral:  m.Integral,
			CreatedAt: util.TimeStdFormat(m.CreatedAt),
		}
	}
	return &pb.AdminSearchMembersReply{
		Total:    total,
		PageNo:   pg.PageNo,
		PageSize: pg.PageSize,
		Members:  rMems,
	}, nil
}

// AdminGetMemberInfo 获取用户信息
func (srv *memberSrv) AdminGetMemberInfo(ctx context.Context, brandId, memberId int64) (*pb.AdminMemberInfoReply, lueerror.LueError) {
	mem, err := dao.GetMemberDao().GetMemberById(ctx, memberId)
	if err != nil {
		return nil, lueerror.DbErr(err)
	}
	if mem == nil || mem.BrandId != brandId {
		return nil, lueerror.MemberNotExist(fmt.Errorf("品牌 %d, 用户 %d 不存在", brandId, memberId))
	}
	return &pb.AdminMemberInfoReply{
		MemberId: mem.Id,
		BrandId:  mem.BrandId,
		Birthday: util.TimeToDate(mem.Birthday),
		Avatar:   mem.Avatar,
		Mobile:   mem.Mobile,
		Email:    mem.Email,
		Nickname: mem.Nickname,
		IsFormal: mem.IsFormal,
		Status:   mem.GetStatus(),
	}, nil
}

// 获取关联会员id
func (srv *memberSrv) getRelatedIds(ctx context.Context, brandId, memberId int64) ([]int64, lueerror.LueError) {
	mIds, err := dao.GetLoginChannelDao().GetRelatedMemberId(ctx, brandId, memberId)
	if err != nil {
		return nil, lueerror.DbErr(err)
	}
	if len(mIds) == 0 {
		return nil, nil
	}
	return mIds, nil
}

// GetMemberRelatedIds 获取关联会员id
func (srv *memberSrv) GetMemberRelatedIds(ctx context.Context, brandId, memberId int64) (*pb.GetRelatedMemberIdsReply, lueerror.LueError) {
	mIds, errL := srv.getRelatedIds(ctx, brandId, memberId)
	if errL != nil {
		return nil, errL
	}
	return &pb.GetRelatedMemberIdsReply{MemberIds: mIds}, nil
}

// GetMemberConsumptionData 获取会员消费记录
func (srv *memberSrv) GetMemberConsumptionData(ctx context.Context, brandId, memberId int64) (*pb.AdminMemberConsumptionReply, lueerror.LueError) {
	mIds, errL := srv.getRelatedIds(ctx, brandId, memberId)
	if errL != nil {
		return nil, errL
	}
	var lastTime, firstTime time.Time
	var count uint32
	var amount uint64
	cData, err := dao.GetMemberAccountDao().GetConsumptionStatByMemberId(ctx, mIds)
	if err != nil {
		return nil, lueerror.DbErr(err)
	}
	for _, d := range cData {
		if util.IsZeroTime(d.CreatedAt) || firstTime.After(d.CreatedAt) {
			firstTime = d.CreatedAt
		}
		if util.IsZeroTime(d.UpdatedAt) || lastTime.Before(d.UpdatedAt) {
			lastTime = d.UpdatedAt
		}
		count += d.Count
		amount += uint64(d.MoneyAmount)
	}
	return &pb.AdminMemberConsumptionReply{
		MemberId:    memberId,
		BrandId:     brandId,
		Count:       count,
		MoneyAmount: amount,
		CreatedAt:   util.TimeToDate(firstTime),
		UpdatedAt:   util.TimeToDate(lastTime),
	}, nil
}

func (srv *memberSrv) getMemberSummery(ctx context.Context, brandId int64, needAjust bool) (*object.AdminMemberStatistic, lueerror.LueError) {
	stat, err := dao.GetMemberDao().GetAdminMemberStatisticCache(ctx, brandId)
	if err != nil {
		return nil, lueerror.RedisErr(err)
	}
	if stat != nil {
		return stat, nil
	}
	todayStart := util.TodayStart()
	userNumBeforeToday, err := dao.GetMemberDao().CountMembersByCreateTime(ctx, brandId, time.Time{}, todayStart)
	if err != nil {
		return nil, lueerror.DbErr(err)
	}
	userNumToday, err := dao.GetMemberDao().CountMembersByCreateTime(ctx, brandId, todayStart, time.Time{})
	if err != nil {
		return nil, lueerror.DbErr(err)
	}
	accNumBeforeToday, err := dao.GetMemberAccountDao().CountAccsByBrandCreateTime(ctx, brandId, time.Time{}, todayStart)
	if err != nil {
		return nil, lueerror.DbErr(err)
	}
	accNumToday, err := dao.GetMemberAccountDao().CountAccsByBrandCreateTime(ctx, brandId, todayStart, time.Time{})
	if err != nil {
		return nil, lueerror.DbErr(err)
	}
	// 第一通过消息通知查询，会重复计算
	if needAjust {
		if userNumToday > 0 {
			userNumToday -= 1
		}
		if accNumToday > 0 {
			accNumToday -= 1
		}
	}
	stat = &object.AdminMemberStatistic{
		BrandId:            brandId,
		HistoryRegisterNum: userNumBeforeToday,
		HistorySendCardNum: accNumBeforeToday,
		TodayRegisterNum:   userNumToday,
		TodaySendCardNum:   accNumToday,
	}
	err = dao.GetMemberDao().CacheAdminMemberStatistic(ctx, stat)
	if err != nil {
		return nil, lueerror.DbErr(err)
	}
	return stat, nil
}

// GetAdminMemberSummery 后台获取用户概况
func (srv *memberSrv) GetAdminMemberSummery(ctx context.Context, brandId int64) (*pb.AdminMemberStatisticReply, lueerror.LueError) {
	stat, errL := srv.getMemberSummery(ctx, brandId, false)
	if errL != nil {
		return nil, errL
	}
	return &pb.AdminMemberStatisticReply{
		BrandId:          brandId,
		RegisterTotal:    stat.HistoryRegisterNum + stat.TodayRegisterNum,
		SendCardTotal:    stat.HistorySendCardNum + stat.TodaySendCardNum,
		TodayRegisterNum: stat.TodayRegisterNum,
		TodaySendCardNum: stat.TodaySendCardNum,
	}, nil
}

// MemberRegisterNotify 会员注册消息
func (srv *memberSrv) MemberRegisterNotify(ctx context.Context, brandId, memberId int64) lueerror.LueError {
	stat, errL := srv.getMemberSummery(ctx, brandId, true)
	if errL != nil {
		return errL
	}
	mem, err := dao.GetMemberDao().GetMemberById(ctx, memberId)
	if err != nil {
		return lueerror.DbErr(err)
	}
	if mem == nil || mem.BrandId != brandId {
		return nil
	}
	stat.TodayRegisterNum += 1
	err = dao.GetMemberDao().CacheAdminMemberStatistic(ctx, stat)
	if err != nil {
		return lueerror.RedisErr(err)
	}
	return nil
}

// CardSendingNotify 发卡消息
func (srv *memberSrv) CardSendingNotify(ctx context.Context, brandId, accId int64) lueerror.LueError {
	stat, errL := srv.getMemberSummery(ctx, brandId, true)
	if errL != nil {
		return errL
	}
	acc, err := dao.GetMemberAccountDao().GetAccById(ctx, accId)
	if err != nil {
		return lueerror.DbErr(err)
	}
	if acc == nil || acc.BrandId != brandId {
		return nil
	}
	stat.TodaySendCardNum += 1
	err = dao.GetMemberDao().CacheAdminMemberStatistic(ctx, stat)
	if err != nil {
		return lueerror.RedisErr(err)
	}
	return nil
}
